#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>


// 13-libevent内部事件的状态转换__recv
int main0001(){

  struct event_base *base =  NULL;
  base = event_base_new();
  // 答应在当前平台内部封装支持的io转接函数
  const char** meths = event_get_supported_methods();
  for(int i=0; meths[i] != NULL ; i++){

      printf("%s\n", meths[i]);
  }
  // 当前使用的io转接函数
  printf("crrent=%s\n",event_base_get_method(base));


// 打印
// epoll
// poll
// select
// crrent=epoll

}


//首先运行read.exe 阻塞，在运行write.exe 写

void read_cb(evutil_socket_t fd, short what, void* arg)
{
     printf("last arg value: %s\n", (char*)arg);

    // 读数据
    char buf[1024] = {0};
    int len= read(fd, buf, sizeof(buf));
    printf("data len= %d, buf: %s\n", len,buf);

    printf("========================\n");
    printf("Read event: %s\n", what & EV_READ ? "Yes" : "No");

    printf("=========== %d\n", what);
}




//14-使用event读管道__recv   
int main(int argc, const char* argv[])
{

    unlink("myfifo");

   // 创建管道文件
    int ret = mkfifo("myfifo", 0664);
    if(ret == -1)
    {
        perror("mkfifo error");
        exit(1);
    }


  // 打开管道文件
    int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
    if(fd == -1)
    {
        perror("open error");
        exit(1);
    }



// 1. 创建新事件  what  6个宏 
//     #define EV_TIMEOUT 0x01      // 废弃
//     #define EV_READ 0x02         //对应  epollin
//     #define EV_WRITE 0x04        // 对于  epllout
//     #define EV_SIGNAL 0x08       // libevent里面也封装了信号相关操作 
//     #define EV_PERSIST 0x10      // 持续触发，持续读， 如果不指定， 读一次只,读出来空也持续读
//     #define EV_ET 0x20           // 边沿模式



//     typedef void (*event_callback_fn)(evutil_socket_t, short, void *); 
//     struct event*  event_new(
//         struct event*  base,           
//         evutil_socket fd ,        //  -  文件描述符- int类型   
//         short what,               //  -  上面的宏  
//         event_callback_fn cb,     // - 事件的处理动作，上面what时间触发了，交给callback_fn处理 
//         void *arg                 // -  给回调传递的value 
// );

// struct event *event_new()函数之后, 新事件处于已初始化和非未决状态

// 原理： event 内部维护一个循环，判断事件是否被调用 
// event_base  libevent引擎 

    struct event_base *base = event_base_new();
    struct event* ev = event_new(base, fd, EV_READ | EV_PERSIST, 
                                 read_cb, "this is write callback func!");

 //2.添加事件 
 // 使用event_add 将事件添加到event_baee,非未决事件->未决事件 
 /***非未决事件: 没有资格被处理
  *  
  * 未决事件： 有资格被处理但是没有处理
  * 
  */
//int event_add( struct event *ev, const struct timeval *tv）

//int event_add(
//        struct event *ev, 
//        const struct timeval *tv
// )

// NULL: 事件被触发, 对应的回调被调用
// tv = {0, 100}, 如果设置的时间，
// 在该时间段内检测的事件没被触发,时间到达之后, 回调函数还是会被调用
// 函数调用成功返回0, 失败返回-1
 

//  int event_del(struct event *ev);
// 这里可以添加fifo,键盘输入事件监听
    event_add(ev, NULL);

//  3. 启动事件循环 
// 可能需要很长事件，一个死循环

// 函数2：  int event_base_loop(struct event_base *base, int flags);
// #define EVLOOP_ONCE 0x01
// 事件只会被触发一次
// 事件没有被触发, 阻塞等

// #define EVLOOP_NONBLOCK 0x02
// 非阻塞 等方式去做事件检测
// 不关心事件是否被触发了 

// #define EVLOOP_NO_EXIT_ON_EMPTY 0x04
// 没有事件的时候, 也不退出轮询检测 

    event_base_dispatch(base);

// 4. 事件不用的时候，释放调
// int event_base_loopexit( struct event_base *base, const struct timeval *tv) 
//  调用了这个函数，如果有一个事件执行到一半了，事件处理完毕才退出循环 
// tv  事件到了，退出，没有事件， 有 如果有一个事件执行到一半了，事件处理完毕才退出循环 

// int event_base_loopbreak(struct event_base *base);   立刻退出循环 
  
    event_free(ev);
    event_base_free(base);

    close(fd);
 
    return 0;
}
